<?php
/**
 * Date: 2024.8
 * Author: kahn
 * 符合psr16标准的redis缓存系统
 */

namespace psr16Cache;

use Psr\SimpleCache\CacheInterface;
use RedisException;

class RedisCache implements CacheInterface
{
    private \Redis $redis;
    private string $prefix = "DB_";

    /**
     * @param $config
     * @throws RedisException
     */
    public function __construct($config)
    {
        $this->redis = new \Redis();
        $this->redis->connect($config['host'], $config['port'], $config['timeout']);
        $this->redis->auth($config['auth']);
        $this->redis->select($config['db']);
    }

    /**
     * @param string $key
     * @param mixed|null $default
     * @return mixed
     * @throws RedisException
     */
    public function get(string $key, mixed $default = null): mixed
    {
        $key = $this->prefix . $key;
        return json_decode($this->redis->get($key), true);
    }

    /**
     * @param string $key
     * @param mixed $value
     * @param int|DateInterval|null $ttl
     * @return bool
     * @throws RedisException
     */
    public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool
    {
        $key = $this->prefix . $key;
        if ($ttl) {
            $res = $this->redis->setex($key, $ttl, json_encode($value));
        } else {
            $res = $this->redis->set($key, json_encode($value));
        }
        return $res;
    }

    /**
     * @param string $key
     * @return bool
     * @throws RedisException
     */
    public function delete(string $key): bool
    {
        $key = $this->prefix . $key;
        return $this->redis->del($key);
    }

    /**
     * @return bool
     * @throws RedisException
     */
    public function clear(): bool
    {
        $keys = $this->redis->keys("{$this->prefix}*");
        return $this->redis->del($keys);
    }

    /**
     * @param iterable $keys
     * @param mixed|null $default
     * @return iterable
     * @throws RedisException
     */
    public function getMultiple(iterable $keys, mixed $default = null): iterable
    {
        $data = [];
        foreach ($keys as $key) {
            $data[$key] = json_decode($this->redis->get($this->prefix . $key), true);
        }
        return $data;
    }

    /**
     * @param iterable $values
     * @param int|DateInterval|null $ttl
     * @return bool
     * @throws RedisException
     */
    public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool
    {
        if ($ttl) {
            foreach ($values as $key => $value) {
                $key = $this->prefix . $key;
                $this->redis->setex($key, $ttl, json_encode($value));
            }
        } else {
            foreach ($values as $key => $value) {
                $key = $this->prefix . $key;
                $this->redis->set($key, json_encode($value));
            }
        }
        return true;
    }

    /**
     * @param iterable $keys
     * @return bool
     * @throws RedisException
     */
    public function deleteMultiple(iterable $keys): bool
    {
        foreach ($keys as &$key) {
            $key = $this->prefix . $key;
        }
        return $this->redis->del($keys);
    }

    /**
     * @param string $key
     * @return bool
     * @throws RedisException
     */
    public function has(string $key): bool
    {
        $key = $this->prefix . $key;
        return $this->redis->exists($key);
    }
}